package kr.co.bnsmedia.touchconfig;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

public class PacketData {
	public static final byte VERSION_LEN = 6;
	public static final byte FWINFO_LEN = 3;
	public static final byte FWDATA_LEN = 4;
	public static final byte TOUCH_CONFIG_LEN = 64 - 4 - 2;	// report_size(64) - packet_header(4) - reserved(2)
	public static final byte CAMERA_CONFIG_LEN = 64 - 4 - 2;	// report_size(64) - packet_header(4) - reserved(2)
	public static final byte RADIAN_LEN = 12;	// float fCenter, fStart, fEnd;

	// hex to byte[]
	public static byte[] hexToByteArray(String hex) {
		byte[] ba = new byte[hex.length() / 2];
		for (int i=0; i<ba.length; i++) {
			ba[i] = (byte)Integer.parseInt(hex.substring(2*i, 2*i + 2), 16);
		}
		return ba;
	}

	// byte[] to hex
	public static String byteArrayToHex(byte[] ba) {
		StringBuffer sb = new StringBuffer(ba.length * 2);
		String hexNumber;
		for (int x=0; x<ba.length; x++) {
			hexNumber = "0" + Integer.toHexString(0xff & ba[x]);
			sb.append(hexNumber.substring(hexNumber.length() - 2));
		}
		return sb.toString();
	}

	public static String uShortToHex(int us) {
		byte[] buf = new byte[2];
		buf[0] = (byte) ((us & 0x0000FF00L) >> 8);
		buf[1] = (byte) (us & 0x000000FFL);
		return byteArrayToHex(buf);
	}
	public static String uIntToHex(long us) {
		byte[] buf = new byte[4];
		buf[0] = (byte) ((us & 0xFF000000L) >> 24);
		buf[1] = (byte) ((us & 0x00FF0000L) >> 16);
		buf[2] = (byte) ((us & 0x0000FF00L) >> 8);
		buf[3] = (byte) (us & 0x000000FFL);
		return byteArrayToHex(buf);
	}

	public static byte[] uShortToByteArray(int aValue) {
		ByteBuffer buff = ByteBuffer.allocate(Character.SIZE / 8);
		buff.order(ByteOrder.LITTLE_ENDIAN);
		buff.putChar((char)aValue);
		return buff.array();
	}
	public static char byteArrayToUshort(int aIdx, byte[] aBuffer) {
		return ByteBuffer.wrap(aBuffer).order(ByteOrder.LITTLE_ENDIAN).getChar(aIdx);
	}

	public static byte[] uIntToByteArray(long aValue) {
		ByteBuffer buff = ByteBuffer.allocate(Integer.SIZE / 8);
		buff.order(ByteOrder.LITTLE_ENDIAN);
		buff.putInt((int)aValue);
		return buff.array();
	}
	public static long byteArrayToUInt(int aIdx, byte[] aBuffer) {
		return ByteBuffer.wrap(aBuffer).order(ByteOrder.LITTLE_ENDIAN).getInt(aIdx);
	}

	public static byte[] floatToByteArray(float aValue) {
		ByteBuffer buff = ByteBuffer.allocate(Float.SIZE / 8);
		buff.order(ByteOrder.LITTLE_ENDIAN);
		buff.putFloat(aValue);
		return buff.array();
	}
	public static float byteArrayToFloat(int aIdx, byte[] aBuffer) {
		return ByteBuffer.wrap(aBuffer).order(ByteOrder.LITTLE_ENDIAN).getFloat(aIdx);
	}
}


class PacketVersion extends PacketData {
	public int wVersion;
	public long dwBuildTime;

	public void set(int aIdx, byte[] aBuffer) {
		wVersion = PacketData.byteArrayToUshort(aIdx, aBuffer);
		dwBuildTime = PacketData.byteArrayToUInt(aIdx+2, aBuffer);
	}

	public String version() {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss", Locale.KOREA);
		Date currentTime = new Date(dwBuildTime*1000);

		String result = PacketData.uShortToHex(wVersion) + ", " + sdf.format(currentTime);
		return result;
	}
}

class PacketFWInfo extends PacketData {
	public byte bType;
	public int wTotalSize;

	public PacketFWInfo() {
	}

	public PacketFWInfo(byte aType, int aTotalSize) {
		bType = aType;
		wTotalSize = aTotalSize;
	}

	public byte[] array() {
		byte[] buffer = new byte[FWINFO_LEN];
		byte[] temp = uShortToByteArray(wTotalSize);

		buffer[0] = bType;
		System.arraycopy(temp, 0, buffer, 1, temp.length);

		return buffer;
	}

	public void set(int aIdx, byte[] aBuffer) {
		bType = aBuffer[aIdx++];
		wTotalSize = PacketData.byteArrayToUshort(aIdx, aBuffer);	aIdx += 2;
	}
}

class PacketFWData extends PacketData {
	public int wCurSize;
	public int wTotalSize;

	public void set(int aIdx, byte[] aBuffer) {
		wCurSize = PacketData.byteArrayToUshort(aIdx, aBuffer);	aIdx += 2;
		wTotalSize = PacketData.byteArrayToUshort(aIdx, aBuffer);	aIdx += 2;
	}
}

class PacketTouchConfig extends PacketData {
	public byte bFilterNum;		// 0 ~ 8 : 0(no correction)
	public byte bInputMode;		// 0(Mouse), 1(Sigle-touch), 2(Multi-touch)
	public byte[] bPWMs = new byte[g.DATA_PWM_NUM];// 0 ~ 100, Ch1~Ch4
	public byte bTimeTap;		//  1 ~ 10 [*100 msec]
	public byte bTimeLTap;		//  1 ~ 80 [*100 msec]
	public byte bAreaTap;		//  1 ~ 15 [*0.1 %]
	public byte bAreaDTap;		// 10 ~ 30 [*0.1 %]
	public byte bAreaPalm;		// 30 ~ 60 [*0.1 %]
	public byte bBeepAlert;		// 0 or 1
	public byte bBeepClick;		// 0 or 1
	public byte bTouchNoSend;	// 0 or 1

	public void set(int aIdx, byte[] aBuffer) {
		int idx = aIdx;

		bFilterNum = aBuffer[idx++];
		bInputMode = aBuffer[idx++];
		for (int i=0; i<g.DATA_PWM_NUM; i++) {
			bPWMs[i] = aBuffer[idx++];
		}
		bTimeTap = aBuffer[idx++];
		bTimeLTap = aBuffer[idx++];
		bAreaTap = aBuffer[idx++];
		bAreaDTap = aBuffer[idx++];
		bAreaPalm = aBuffer[idx++];
		bBeepAlert = aBuffer[idx++];
		bBeepClick = aBuffer[idx++];
		bTouchNoSend = aBuffer[idx++];
	}
}

class PacketCameraConfig extends PacketData {
	public short nYCenter;		// -300 ~ 300
	public short wXStart;		// 0 ~ 400
	public short wXEnd;			// 600 ~ 1023
	public short bThreshold;		// 0 ~ 255
	public byte bMinWidth;		// 1~5
	public short bAverageLight;	// 0 ~ 255
	public float[] fCoeffs = new float[g.DATA_COEFFS_NUM];

	public void set(int aIdx, byte[] aBuffer) {
		int idx = aIdx;

		nYCenter = (short)PacketData.byteArrayToUshort(idx, aBuffer);	idx += 2;
		wXStart = (short)PacketData.byteArrayToUshort(idx, aBuffer);	idx += 2;
		wXEnd = (short)PacketData.byteArrayToUshort(idx, aBuffer);	idx += 2;
		bThreshold = (short)(aBuffer[idx++] & 0xFF);
		bMinWidth = (byte)(aBuffer[idx++] & 0xFF);
		bAverageLight = (short)(aBuffer[idx++] & 0xFF);
		for (int i=0; i<g.DATA_COEFFS_NUM; i++) {
			fCoeffs[i] = PacketData.byteArrayToFloat(idx, aBuffer);	idx += 4;
		}
	}
}

class PacketRadian extends PacketData {
	public float fCenter;
	public float fStart;
	public float fEnd;

	public void set(int aIdx, byte[] aBuffer) {
		int idx = aIdx;
		fCenter = PacketData.byteArrayToFloat(idx, aBuffer);	idx += 4;
		fStart = PacketData.byteArrayToFloat(idx, aBuffer);	idx += 4;
		fEnd = PacketData.byteArrayToFloat(idx, aBuffer);	idx += 4;
	}
}
